package cn.dapeng.tree.multi;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 实现
 *  1.多叉树格式化输出
 *  2.多叉树查找
 */
public class MultiTreeCreator {

    public static final Map<Character, MultiTree> CACHE = new HashMap<>();


    public static void createMultiTree(String word) {
        if (word == null || word.length() < 2) {
            return;
        }
        char[] chars = word.toCharArray();
        int length = chars.length;

        char firstChar = chars[0];

        MultiTree head = CACHE.computeIfAbsent(firstChar, MultiTree::new);

        for (int i = 1; i < length; i++) {
            MultiTree nextNode = new MultiTree(chars[i], i);

            if (head.isLeaf() || !head.getChildren().containsKey(chars[i])) {
                head.addChild(nextNode);
                head = nextNode;
                continue;
            }

            nextNode = head.getChildren().get(chars[i]);
            head = nextNode;
        }

    }

    public static void formatToString(FormatType formatType) {
        if (formatType.equals(FormatType.TAB)) {
            for (MultiTree node : CACHE.values()) {
                printWithTab(node, 0);
            }
        } else {
            for (MultiTree node : CACHE.values()) {
                printWithLine(node, false);
                System.out.println();
            }
        }
    }

    public static void printWithLine(MultiTree head, boolean repeat) {
        //System.out.print((repeat ? "XX".repeat(head.getDeep()) : "") + head.getChars());
        System.out.print((repeat ? "  ".repeat(head.getDeep()) : "") + head.getChars());
        if (head.isLeaf()) {
            System.out.println();
            return;
        }
        Map<Character, MultiTree> map = head.getChildren();
        if (map != null && !map.isEmpty()) {
            List<Character> list = map.keySet().stream().toList();
            for (int i = 0; i < list.size(); i++) {
                char c = list.get(i);
                if (i > 0) {
                    printWithLine(map.get(c), true);
                } else {
                    printWithLine(map.get(c), false);
                }

            }
        }
    }

    public static void printWithTab(MultiTree head, int level) {
        System.out.println("\t".repeat(level) + head.getChars());
        if (head.getChildren() != null && !head.getChildren().isEmpty()) {
            level++;
            for (char c : head.getChildren().keySet()) {
                printWithTab(head.getChildren().get(c), level);
            }
        }
    }

    public static boolean contains(String word) {
        if (!CACHE.containsKey(word.charAt(0))) {
            return false;
        }

        int length = word.length();
        MultiTree head = CACHE.get(word.charAt(0));

        loop:
        for (int i = 0; i < length; i++) {

            if (!find(head, word.charAt(i))) {
                continue;
            }

            if (head.isLeaf() && i == length - 1) {
                return true;
            }

            Map<Character, MultiTree> children = head.getChildren();

            if (children == null || children.isEmpty()) {
                return false;
            }

            for (char c : children.keySet()) {
                if (++i < length && find(children.get(c), word.charAt(i))) {

                    if (children.get(c).isLeaf() && i >= length - 1) {
                        return true;
                    }

                    if (i + 1 >= length) {
                        return false;
                    }

                    if (children.get(c).isLeaf() && i + 1 <= length - 1) {
                        return false;
                    }

                    head = children.get(c).getChildren().get(word.charAt(i + 1));
                    continue loop;
                } else {
                    --i;
                    //System.out.println("not find ");
                }

            }
            return false;

        }

        return false;
    }

    public static boolean find(MultiTree node, char ch) {
        //System.out.println("find " + ch + " in " + ((node != null) ? node.getChars() : "NULL"));
        return node != null && node.getChars() == ch;
    }

    /**
     * 格式化类型
     */
    public enum FormatType {
        TAB, Line
    }

    public static void main(String[] args) {
        createMultiTree("败一千本");
        createMultiTree("败门");
        System.out.println(contains("败败门"));
    }
}
